*! ivreset 1.0.08  4Feb2007

*! author mes

* Z are instruments (L of them) and X are regressors (K of them)

* 1.0.04  Fixed small bug in check for xtmodel

*         Fixed dof check in xtivreg2

* 1.0.05  Changed rescaling so that squares, cubes, etc are created then rescaled

* 1.0.06  Removed rescaling, switched to -orthog-

*         Removed support for official ivreg

*         Fixed small bug in failed cstat reporting

* 1.0.07  Added trap to catch usage after ivreg2 with fwl

* 1.0.08  Refined trap



program define ivreset, rclass sortpreserve

	version 8.0

	local version 1.0.8



	syntax [, POLYnomial(integer 2) RForm cstat small] 



	if "`e(cmd)'" != "ivreg2" & "`e(cmd)'" != "regress" & /*

			*/	"`e(cmd)'" != "ivreg3" & "`e(cmd)'" != "xtivreg2" {

		error 301

	}



	if "`e(cmd)'" == "xtivreg2" & "`e(xtmodel)'" ~= "fe" {

		error 301

	}



	if "`e(fwlcons)'" != "" {

di in r "ivreset not allowed after ivreg2 with fwl option"

		error 499

	}



	if "`cstat'" != "" {

* Check that ivreg2 is installed when cstat option is requested

		capture findfile ivreg2.ado

		if _rc==601 {

di as err "Error: installed ivreg2 required for cstat option"

			error 601

		}

	}



	tempvar  touse N yhat yhat2 yhat3 yhat4

	tempname regest b



* Default is to use Pesaran-Smith optimal forecast of y

	if "`rform'" == "" {

		local msg0 "Ramsey/Pesaran-Taylor RESET test"

		local msg2 "fitted value of y (X-hat*beta-hat)"

	}

	else {

		local msg0 "Ramsey/Pagan-Hall RESET test"

		local msg2 "reduced form prediction of y"

	}



	if "`cstat'" == "" {

		local msg3 "Wald"

	}

	else {

		local msg3 "C (GMM-distance)"

	}



	if "`e(vcetype)'"=="Robust" {

		local robust "robust"

		local msg3h "heteroskedastic-"

	}	



	if "`e(clustvar)'"~="" {

		local clopt "cluster(`e(clustvar)')"

		local msg3c "cluster-"

	}



	if "`e(bw)'"~="" {

		local bwopt "bw(`e(bw)')"

		local kernopt "kernel(`e(kernel)')"

		local msg3a "autocorrelation-"

	}



	if "`e(wtype)'" != "" {

		local wtexp `"[`e(wtype)'`e(wexp)']"'

	}



	gen `touse'=e(sample)



	mat `b' = e(b)

	local rhs : colnames `b'

	local rhsct : word count `rhs'

	local depvar "`e(depvar)'"

	local df_m = e(df_m)



	if "`e(cmd)'" != "regress" {

* Block for all IV commands

		local endo "`e(instd)'"

		local insts "`e(insts)'"

		foreach vn of local rhs {

			local tempvlist : subinstr local insts "`vn'" "`vn'" , /*

				*/ word count(local isiv)

			if `isiv'==1 {

				local inexog "`inexog' `vn'"

			}

		}

		foreach vn of local insts {

			local tempvlist : subinstr local rhs "`vn'" "`vn'" , /*

				*/ word count(local isregressor)

			if `isregressor'==0 {

				local exexog "`exexog' `vn'"

			}

		}

	* If endo is empty, it's OLS or HOLS, and if so, ignore exexog as well

		if "`endo'"=="" {

			local exexog

		}

		if e(cons)~=1 {

			local consflag 0

			local consopt "nocons"

		}

		else {

			local consflag 1

		}

	}

	else {

* Block for simple regress

		local endo

		local exexog

		local inexog : subinstr local rhs "_cons" "", word count(local consflag)

		if `consflag'==0 {

			local consopt "nocons"

		}

	}



* If no endogenous regressors, it's just a simple RESET test

	if "`endo'" == "" {

		local msg0 "Ramsey RESET test"

		local msg2 "fitted value of y (X*beta-hat)"

	}



* Demeaning block for xtivreg2

	if "`e(cmd)'" == "xtivreg2" {

		preserve

		tempvar ivar T_i depvar2

		qui gen double `depvar2' = `depvar'

		qui gen `ivar' = `e(ivar)'

		sort `ivar' `touse'

		qui by `ivar' `touse': gen long `T_i' = _N if _n==_N & `touse'

		qui count if `T_i' < .

* N_g minus 1 is additional degrees of freedom absorbed by the extra dummies

		local N_g=r(N)

		local allvars "`depvar' `inexog' `endo' `exexog'"		

		qui foreach var of local allvars {

			tempname `var'_m

			by `ivar' `touse' : gen double ``var'_m'=sum(`var')/_N if `touse'

			by `ivar' `touse' : replace    ``var'_m'=``var'_m'[_N] if `touse' & _n<_N

			by `ivar' `touse' : replace `var'=`var'-``var'_m'[_N]           if `touse'

		}

* Small degrees of freedom = N minus #regressors minus #fixed effects (+constant)

* Large = N minus #fixed effects

		qui sum `depvar' if `touse'

		local N=r(N)

* Use only large dof, not small. Subtract full number of fixed effects `N_g'

		local dof = `N' - `N_g'

* nocons not part of xtopts - caught below

		local xtopts "dofminus(`N_g')"

	}

		

	if "`rform'" == "" {

* Code for Pesaran-Smith test using "predicted" values "yhat"=xhat*Bhat (NOT x*Bhat)

* Generate predicted values of endog regressors

* In special case of no endog regressors (OLS or HOLS), exexog has also been set to empty

* and yhat is just the usual OLS/HOLS yhat

		foreach vn of local endo {

			capture _estimates hold `regest', restore

			qui regress `vn' `inexog' `exexog' `wtexp' if `touse', `consopt'

			tempvar xh

			qui predict double `xh' if `touse', xb

			capture _estimates unhold `regest'

			local endohat "`endohat' `xh'"

		}

		local rhshat "`endohat' `inexog'"

		mat `b' = e(b)

		if `consflag' {

			local rhshat "`rhshat' _cons"

		}

		matrix colnames `b' = `rhshat'

		matrix score double `yhat' = `b' if `touse'

	}

	

	if "`rform'" != "" {

* Code for Pagan-Hall test using reduced form predictions

* In special case of no endog regressors (OLS or HOLS), exexog has also been set to empty

* and yhat is just the usual OLS/HOLS yhat

		capture _estimates hold `regest', restore

		qui regress `depvar' `inexog' `exexog' `wtexp', `consopt'

		qui predict double `yhat', xb

		capture _estimates unhold `regest'

	}



* Add mean back to yhat if xtivreg2

	qui if "`e(cmd)'" == "xtivreg2" {

		tempname depvar_m

		by `ivar' `touse' : gen double `depvar_m'=sum(`depvar2')/_N if `touse'

		by `ivar' `touse' : replace    `depvar_m'=`depvar_m'[_N] if `touse' & _n<_N

		by `ivar' `touse' : replace `yhat'  =`yhat'  +`depvar_m'[_N] if `touse'

	}



* Generate squares, and cube/4th powers if requested.  Always need yhat^2.

* Orthogonalize if order>3.

	qui gen double `yhat2'=`yhat'^2

	if `polynomial'==2 {

		local yhats "`yhat2'"

		local msg1 "square of "

	}

	if `polynomial'==3 {

		tempname yhat2o yhat3o

		qui gen double `yhat3'=`yhat'^3

		orthog `yhat2' `yhat3' if `touse', gen(`yhat2o' `yhat3o')

		qui replace `yhat2'=`yhat2o'

		qui replace `yhat3'=`yhat3o'

		local yhats "`yhat2' `yhat3'"

		local msg1 "square and cube of "

	}

	if `polynomial'==4 {

		tempname yhat2o yhat3o yhat4o

		qui gen double `yhat3'=`yhat'^3

		qui gen double `yhat4'=`yhat'^4

		orthog `yhat2' `yhat3' `yhat4' if `touse', gen(`yhat2o' `yhat3o' `yhat4o')

		qui replace `yhat2'=`yhat2o'

		qui replace `yhat3'=`yhat3o'

		qui replace `yhat4'=`yhat4o'

		local yhats "`yhat2' `yhat3' `yhat4'"

		local msg1 "square, cube and 4th power of "

	}



* Demean yhats

	if "`e(cmd)'" == "xtivreg2" {

		qui foreach var of local yhats {

			tempname `var'_m

			by `ivar' `touse' : gen double ``var'_m'=sum(`var')/_N if `touse'

			by `ivar' `touse' : replace ``var'_m'=``var'_m'[_N] if `touse' & _n<_N

			by `ivar' `touse' : replace `var'=`var'-``var'_m'[_N] if `touse'

		}

	}



* Artificial regression test (default)

	if "`cstat'"=="" {

		capture _estimates hold `regest', restore

		if "`endo'" != "" {

			capture ivreg2 `depvar' `inexog' `yhats' (`endo'=`exexog') `wtexp' if `touse', /*

				*/	`small' `xtopts' `robust' `clopt' `bwopt' `kernopt' `consopt'

		}

		else {

* No endogenous regressors, so ignore excluded exog (if any) as well

			capture ivreg2 `depvar' `inexog' `yhats' `wtexp' if `touse', /*

				*/	`small' `xtopts' `robust' `clopt' `bwopt' `kernopt' `consopt'

		}

		if "`e(cmd)'" == "xtivreg2" {

			local df_aug = (`N_g'+e(df_m)-(`polynomial'-1))

		}

		else {

			local df_aug = (e(df_m)-(`polynomial'-1))

		}

		if `df_aug' < `df_m' {

di as err "Error - collinearities in augmented regression equation."

di as err "If using higher order polynomials, try reducing the order."

			error 103

		}

		else {

			capture test `yhats'

			return scalar df=r(df)

			return scalar p=r(p)

			if "`small'" == "" {

				return scalar chi2=r(chi2)

			}

			else {

				return scalar F=r(F)

				return scalar df_r=r(df_r)

			}

		}

		capture _estimates unhold `regest'

	}



* Cstat test (GMM distance)

	if "`cstat'" != "" {

		capture _estimates hold `regest', restore

* If endo is empty, so is exexog and it's just an LM test

		qui ivreg2 `depvar' `inexog' (`endo'=`exexog' `yhats') `wtexp' if `touse', /*

			*/	orthog(`yhats') `small' `xtopts' `robust' `clopt' `bwopt' `kernopt' `consopt'

		if e(cstat) > 0 & e(cstat) < . {

			tempname cstat

				scalar `cstat'=e(cstat)

				return scalar df=e(cstatdf)

				return scalar p=e(cstatp)

			if "`small'" == "" {

				return scalar chi2=`cstat'

			}

			else {

				return scalar df_r=e(Fdf2)-return(df)

				return scalar F=`cstat'/return(df)*return(df_r)/e(N)

			}

		}

		capture _estimates unhold `regest'

	}



di in g "`msg0'"

di in g "Test uses `msg1'`msg2'"

di in g "Ho: E(y|X) is linear in X"



	if return(chi2)~=. | return(F)~=. {

		if "`small'"=="" {

di in g "`msg3' test statistic: "   /*

		*/ _col(35) in g "Chi-sq(" return(df)  ") = " /*

		*/ in y %5.2f return(chi2) /* 

		*/ _col(55) in g "P-value = " /*

		*/ in y %5.4f return(p)

		}

		else {

di in g "`msg3' test statistic: "   /*

		*/ _col(35) in g "F(" return(df) "," return(df_r)  ") = " /*

		*/ in y %5.2f return(F) /* 

		*/ _col(55) in g "P-value = " /*

		*/ in y %5.4f return(p)

		}

		if "`msg3h'`msg3c'`msg3a'" ~= "" {

di in g "Test is `msg3h'`msg3c'`msg3a'robust"

		}

	}

	else {

di as err "Error in estimating augmented equation - statistic not reported"

	}



end

